﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NewDevice.USB
{
    /// <summary>
    /// DL3021A 可编程直流电子负载控制类
    /// 提供通过 SCPI 协议控制 DL3021A 电子负载的完整接口
    /// </summary>
    /// <remarks>
    /// 典型应用场景：
    /// 1. 电源测试
    /// 2. 电池放电测试
    /// 3. 功率器件测试
    /// </remarks>
    public class DL3021A : SCPIBase
    {
        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="devName"></param>
        public DL3021A(string devName = "DL3021A") : base(devName) { }

        /// <summary>
        /// 设置电子负载的输入开关状态
        /// </summary>
        /// <param name="status">true: 开启电子负载输入, false: 关闭电子负载输入</param>
        /// <example>
        /// <code>
        /// var load = new DL3021A();
        /// load.SetOutputStatus(true);  // 开启负载
        /// </code>
        /// </example>
        public void SetOutputStatus(bool status)
        {
            string strSts = status ? "1" : "0";
            SendCmd($":SOUR:INP:STAT {strSts}");
        }

        /// <summary>
        /// 获取电子负载当前输入状态
        /// </summary>
        /// <returns>true: 输入已开启, false: 输入已关闭</returns>
        /// <remarks>
        /// 返回值为字符串"1"或"0"的布尔转换
        /// </remarks>
        public bool GetOutputStatus()
        {
            var ret = Query($":SOUR:INP:STAT?");
            return ret == "1";
        }

        /// <summary>
        /// 设置电子负载工作模式
        /// </summary>
        /// <param name="mode">要设置的工作模式</param>
        /// <exception cref="ArgumentException">当传入无效模式时抛出</exception>
        public void SetMode(DL3021A_Mode mode)
        {
            switch (mode)
            {
                case DL3021A_Mode.CC:
                    SendCmd($":SOUR:FUNC CURR");
                    break;

                case DL3021A_Mode.CV:
                    SendCmd($":SOUR:FUNC VOLT");
                    break;

                case DL3021A_Mode.CR:
                    SendCmd($":SOUR:FUNC RES");
                    break;

                case DL3021A_Mode.CP:
                    SendCmd($":SOUR:FUNC POW");
                    break;

                default:
                    throw new ArgumentException("无效的工作模式");
            }
        }

        /// <summary>
        /// 获取电子负载当前工作模式
        /// </summary>
        /// <returns>当前工作模式枚举值</returns>
        /// <exception cref="InvalidOperationException">当设备返回无效模式字符串时抛出</exception>
        public DL3021A_Mode GetMode()
        {
            var ret = Query($":SOUR:FUNC?");
            try
            {
                return (DL3021A_Mode)Enum.Parse(typeof(DL3021A_Mode), ret);
            }
            catch
            {
                throw new InvalidOperationException($"设备返回了未知模式: {ret}");
            }
        }

        /// <summary>
        /// 设置指定模式下的量程范围
        /// </summary>
        /// <param name="mode">工作模式</param>
        /// <param name="range">要设置的量程</param>
        /// <exception cref="ArgumentException">
        /// 当模式与量程不匹配或模式为CP时抛出
        /// </exception>
        public void SetRang(DL3021A_Mode mode, DL3021A_Range range)
        {
            switch (mode)
            {
                case DL3021A_Mode.CC:
                    SendCmd($":SOUR:CURR:RANG {(int)range}");
                    break;

                case DL3021A_Mode.CV:
                    SendCmd($":SOUR:VOLT:RANG {(int)range}");
                    break;

                case DL3021A_Mode.CR:
                    SendCmd($":SOUR:RES:RANG {(int)range}");
                    break;

                case DL3021A_Mode.CP:
                default:
                    throw new ArgumentException("CP模式不支持设置量程");
            }
        }

        /// <summary>
        /// 获取指定模式下的当前量程
        /// </summary>
        /// <param name="mode">工作模式</param>
        /// <returns>当前量程枚举值</returns>
        /// <exception cref="ArgumentException">
        /// 当模式为CP或传入无效模式时抛出
        /// </exception>
        public DL3021A_Range GetRange(DL3021A_Mode mode)
        {
            string ret = "";
            switch (mode)
            {
                case DL3021A_Mode.CC:
                    ret = Query($":SOUR:CURR:RANG?");
                    return (DL3021A_Range)int.Parse(ret);

                case DL3021A_Mode.CV:
                    ret = Query($":SOUR:CURR:VOLT?");
                    return int.Parse(ret) == (int)DL3021A_Range.CV_15V ? DL3021A_Range.CV_15V : DL3021A_Range.CV_150V;

                case DL3021A_Mode.CR:
                    ret = Query($":SOUR:CURR:RES?");
                    return int.Parse(ret) == (int)DL3021A_Range.CR_15 ? DL3021A_Range.CR_15 : DL3021A_Range.CR_15000;

                case DL3021A_Mode.CP:
                default:
                    throw new ArgumentException("CP模式不支持获取量程");
            }
        }

        /// <summary>
        /// 在CC(恒流)模式下设置电流值(安培)
        /// </summary>
        /// <param name="val">要设置的电流值(单位：A)</param>
        /// <remarks>
        /// 必须在CC模式下使用才有效
        /// </remarks>
        public void SetCurrentCC(double val)
        {
            SendCmd($":SOUR:CURR:LEV:IMM {val}");
        }

        /// <summary>
        /// 在CV(恒压)模式下设置电压值(伏特)
        /// </summary>
        /// <param name="val">要设置的电压值(单位：V)</param>
        /// <remarks>
        /// 必须在CV模式下使用才有效
        /// </remarks>
        public void SetVoltageCV(double val)
        {
            SendCmd($":SOUR:VOLT:LEV:IMM {val}");
        }

        /// <summary>
        /// 在CR(恒阻)模式下设置电阻值(欧姆)
        /// </summary>
        /// <param name="val">要设置的电阻值(单位：Ω)</param>
        /// <remarks>
        /// 必须在CR模式下使用才有效
        /// </remarks>
        public void SetResCR(double val)
        {
            SendCmd($":SOUR:RES:LEV:IMM {val}");
        }

        /// <summary>
        /// 在CP(恒功率)模式下设置功率值(瓦特)
        /// </summary>
        /// <param name="val">要设置的功率值(单位：W)</param>
        /// <remarks>
        /// 必须在CP模式下使用才有效
        /// </remarks>
        public void SetPowCP(double val)
        {
            SendCmd($":SOUR:POW:LEV:IMM {val}");
        }

        /// <summary>
        /// 获取CC模式下设定的电流值
        /// </summary>
        /// <returns>当前设定的电流值(单位：A)</returns>
        public double GetCurrentCC()
        {
            var ret = Query($":SOUR:CURR:LEV:IMM?");
            return double.Parse(ret);
        }

        /// <summary>
        /// 获取CV模式下设定的电压值
        /// </summary>
        /// <returns>当前设定的电压值(单位：V)</returns>
        public double GetVoltageCV()
        {
            var ret = Query($":SOUR:VOLT:LEV:IMM?");
            return double.Parse(ret);
        }

        /// <summary>
        /// 获取CR模式下设定的电阻值
        /// </summary>
        /// <returns>当前设定的电阻值(单位：Ω)</returns>
        public double GetResCV()
        {
            var ret = Query($":SOUR:RES:LEV:IMM?");
            return double.Parse(ret);
        }

        /// <summary>
        /// 测量当前输入电压
        /// </summary>
        /// <returns>测量到的电压值(单位：V)</returns>
        public double MeasVoltage()
        {
            var ret = Query($":MEAS:VOLT:DC?");
            return double.Parse(ret);
        }

        /// <summary>
        /// 测量当前输入电流
        /// </summary>
        /// <returns>测量到的电流值(单位：A)</returns>
        public double MeasCurrent()
        {
            var ret = Query($":MEAS:CURR:DC?");
            return double.Parse(ret);
        }

        /// <summary>
        /// 测量当前输入功率
        /// </summary>
        /// <returns>测量到的功率值(单位：W)</returns>
        public double MeasPow()
        {
            var ret = Query($":MEAS:POW:DC?");
            return double.Parse(ret);
        }
    }

    /// <summary>
    /// DL3021A 电子负载的量程范围枚举
    /// </summary>
    public enum DL3021A_Range
    {
        /// <summary>
        /// 恒流模式4A量程
        /// </summary>
        CC_4A = 4,

        /// <summary>
        /// 恒流模式40A量程
        /// </summary>
        CC_40A = 40,

        /// <summary>
        /// 恒压模式15V量程
        /// </summary>
        CV_15V = 15,

        /// <summary>
        /// 恒压模式150V量程
        /// </summary>
        CV_150V = 150,

        /// <summary>
        /// 恒阻模式15Ω量程
        /// </summary>
        CR_15 = 15,

        /// <summary>
        /// 恒阻模式15000Ω量程
        /// </summary>
        CR_15000 = 15000
    }

    /// <summary>
    /// DL3021A 电子负载的工作模式枚举
    /// </summary>
    public enum DL3021A_Mode
    {
        /// <summary>
        /// 恒流模式(Constant Current)
        /// </summary>
        CC,

        /// <summary>
        /// 恒压模式(Constant Voltage)
        /// </summary>
        CV,

        /// <summary>
        /// 恒阻模式(Constant Resistance)
        /// </summary>
        CR,

        /// <summary>
        /// 恒功率模式(Constant Power)
        /// </summary>
        CP
    }
}